import java.util.Objects;

/**
 * Creared with IntelliJ IDEA.
 * Description:
 * User:yxd
 * Date:2022-02-28
 * Time:22:23
 */
class  Person{
    public String ID;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(ID, person.ID);
    }

    @Override
    public int hashCode() {
        return Objects.hash(ID);
    }

    public Person(String ID) {
        this.ID = ID;
    }

    @Override
    public String toString() {
        return "Person{" +
                "ID='" + ID + '\'' +
                '}';
    }
}
public class MyHashBuck2<K,V> {
    private static final double DEFAULT_LOADFACTOR = 0.75;//默认的负载因子
    static class Node<K,V>{
        public K key;
        public V val;
        public Node<K,V> next;
        public Node(K key,V val){
            this.key = key;
            this.val = val;
        }
    }
    public Node<K,V>[] array = (Node<K,V>[])new Node[10];
    public int usedSize;

    public void put(K key,V val){
        int index = key.hashCode() % array.length;
        Node<K,V> cur = array[index];//2.遍历这个下标的元素看有没有这个key
        while(cur != null){
            if(cur.key.equals(key)){
                cur.val = val;//更新
                break;
            }
            cur = cur.next;
        }
        //3.没这个key的元素，需要尾插或者头插
        cur = array[index];
        Node<K,V> node = new Node<>(key,val);
        if(cur == null){
            array[index] = node;
        }else{
            while(cur.next != null){
                cur = cur.next;
            }
            cur.next = node;
        }
        this.usedSize++;
        //4.检查负载因子是否超出，如果超出需要扩容
        if(loadFactor() > DEFAULT_LOADFACTOR){
            resize();
        }
    }
    //隐藏类的实现细节，需要给特定的方法封装一下
    private void resize(){
        //扩容不仅仅是扩大数组长度，应该把所有的元素重新哈希一遍，保证合理利用空间，且所有元素都应在其扩容后应在的位置
        Node<K,V>[] newArray = (Node<K,V>[])new Node[array.length * 2];
        for(int i = 0;i < array.length;i ++){
            Node<K,V> cur = array[i];
            while(cur != null){
                int index = cur.key.hashCode() % newArray.length;
                Node<K,V> curNext = cur.next;//保存这个节点之后的节点，方便后面的节点再放到新数组中
                //以头插或者尾插的方式再放到新链表里面
                //尾插
                if(newArray[index] == null){
                    newArray[index] = cur;
                    newArray[index].next = null;
                }else{
                    Node<K,V> z = newArray[index];
                    while(z.next != null){
                        z = z.next;
                    }
                    z.next = cur;
                    z = z.next;
                    z.next = null;
                }
                cur = curNext;
                //头插
                /*cur.next = newArray[index];//先绑定后面
                newArray[index] = cur;//在绑定前面
                cur = curNext;*/
            }
        }
        array = newArray;
    }
    private double loadFactor(){//获得此时的负载因子
        return 1.0 * usedSize / array.length;
    }

    public V get(K key){
        int index = key.hashCode() % array.length;//1.找到key所在的位置
        Node<K,V> cur = array[index];//2.遍历这个下标的元素看有没有这个key
        while(cur != null){
            if(cur.key.equals(key)){
                return cur.val;
            }
            cur = cur.next;
        }
        return null;//没找到
    }



    public static void main(String[] args) {
        //hashCode  通过hashCode可以将非数字的类型转换为数字然后再进行链地址法插入
        Person person1 = new Person("610");
        Person person2 = new Person("610");
        //此时两个人是不一样的，但是身份证号相同通过hashCode转换会放到相同的位置，我们认为是相同的，因此我们需要重写hashCode和equals方法
        //引用类型要找到相同的必须使用equals，hashCode将引用的值变成整数确定位置
        //hashCode一样equals不一定一样，equals一样hashCode一定一样
        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());

        System.out.println(person1.equals(person2));
        MyHashBuck2<Person,String> myHashBuck2 = new MyHashBuck2<>();
        myHashBuck2.put(person1,"bit");
        System.out.println(myHashBuck2.get(person2));//此时两个所对应的val值是一样的
    }
}
